﻿#include "Field.h"

namespace P
{
__device__ uint256_t *MODULUS = nullptr;
__device__ uint256_t *EDWARDS_A = nullptr;
__device__ uint256_t *EDWARDS_D = nullptr;
}

//Field
__device__ Field Field::zero()
{
	uint256_t zero = 0;
	return Field::constant(zero);
}

__device__ Field Field::one()
{
	return Field::constant((uint256_t)1);
}

__device__ Field Field::create(Mode mode, uint256_t v)
{
	assert(v < *P::MODULUS);

	Field f;
	f.mode = mode;
	f.b = v;
	return f;
}

__device__ Field Field::constant(uint256_t v)
{
	return Field::create(Constant, v);
}

__device__ Field Field::fromBitsLe(const BitArray& bits)
{
	Mode mode = Constant;
	CuByteArray buffer = bits_to_bytes_le(bits);

	Field f;
	f.mode = bitArrayMode(bits);
	memcpy(f.b.data,buffer.data(),buffer.size());
	return f;
}

__device__ Field Field::fromBitsBe(const BitArray& bits)
{
	auto tmp = bits;
	tmp.reverse();
	return fromBitsLe(tmp);
}

__device__ Field Field::from_boolean(Boolean b)
{
	return booleanToField(b);
}

__device__ Field::Field()
{
	mode = Constant;
	b = 0;
}

__device__ CuString Field::toString() const
{
	CuString str = b.toString() + "field";
	str = str + "." + modeText(mode);
	return str;
}

__device__ bool Field::is_constant() const
{
	return mode == Constant;
}

__device__ BitArray Field::toBitsLe() const
{
	CuByteArray bytes(32,0);
	memcpy(bytes.data(),b.data,32);

	BitArray ret = bytes_to_bits_le(bytes);
	for (int i = 0; i < ret.size(); i++)
		ret[i].mode = this->mode;

	return ret.mid(0,253);
}

__device__ BitArray Field::toBitsBe() const
{
	auto ret = toBitsLe();
	ret.reverse();
	return ret;
}

__device__ Field Field::operator+(const Field& other) const
{
	uint256_t ret = b + other.b;
	if (ret >= *P::MODULUS)
		ret = ret - *P::MODULUS;

	return Field::create(calcMode(mode, other.mode), ret);
}

__device__ Field Field::operator-(const Field& other) const
{
	uint256_t ret;
	if (b < other.b)
		ret = b + *P::MODULUS - other.b;
	else
		ret = b - other.b;

	return Field::create(calcMode(mode, other.mode), ret);
}

__device__ Field Field::operator*(const Field& other) const
{
	uint512_t c_b = b;
	uint512_t c_o_b = other.b;
	uint512_t ret = (c_b * c_o_b) % *P::MODULUS;
	return Field::create(calcMode(mode, other.mode), (uint256_t)ret);
}

__device__ bool Field::operator==(const Field& other) const
{
	return b == other.b;
}

__device__ bool Field::operator!=(const Field& other) const
{
	return b != other.b;
}

// 扩展欧几里得算法，用于求ax + by = gcd(a, b)中的x和y以及gcd(a, b)
int512_t extended_gcd(int512_t a, int512_t b, int512_t& x, int512_t& y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int512_t x1, y1;
	int512_t d = extended_gcd(b, a % b, x1, y1);
	x = y1;
	y = x1 - (a / b) * y1;
	return d;
}

// 在有限域GF(p)中求元素a的逆元
int512_t finite_field_inverse(int512_t a, int512_t p) {
	if (a == 0)
		return 0;

	int512_t x, y;
	int512_t gcd = extended_gcd(a, p, x, y);
	if (gcd != 1) {
		// 如果a和p不互质，则a在有限域GF(p)中不存在逆元，这里简单返回 -1表示错误情况
		return -1;
	}
	// 确保返回的逆元是在 [0, p-1] 范围内的正整数表示
	return ((x % p + p) % p);
}

__device__ Field Field::inverse() const
{
	int512_t a = b;
	int512_t p = *P::MODULUS;

	int512_t ret = finite_field_inverse(a, p);
	return Field::create(mode, (uint256_t)(uint512_t)ret);
}

__device__ Boolean Field::msb()
{
	int ret = b.data[7] & (1 << 28);
	if (ret)
		return Boolean::create(mode, true);
	else
		return Boolean::create(mode, false);
}

__device__ CuDebug operator<<(CuDebug dbg, const Field& f)
{
	dbg << f.toString();
	return dbg;
}

//Integer
__device__ Integer Integer::zero(int type)
{
	return constant(type, 0);
}

__device__ Integer Integer::create(int type, Mode mode, cpp_int value)
{
	Integer i;
	i.m_type = type;
	i.m_mode = mode;
	if (value < 0 && !typeIsSign(type))
		value = integerMax(type) + value + 1;
	i.m_value = value;
	i.normalize();
	return i;
}

__device__ Integer Integer::constant(int type, cpp_int value)
{
	return create(type, Constant, value);
}

__device__ Integer Integer::fromField(int type, const Field& f)
{
	return Integer::fromBitsLe(type, f.toBitsLe());
}

__device__ Integer Integer::fromBitsLe(int type, const BitArray& bits)
{
	int byte_size = typeBitSize(type)/8;
	CuByteArray bytes = bits_to_bytes_le(bits);

	Integer i;
	i.m_type = type;
	i.m_mode = bitArrayMode(bits);
	memcpy(i.m_value.data,bytes.data(), byte_size);

	if(typeIsSign(type) && i.msb().value)
	{
		uint8_t* ptr = (uint8_t*)i.m_value.data;
		for (int i = byte_size; i < 32; i++)
			ptr[i] = 0xFF;
	}
	return i;
}

__device__ Integer::Integer()
{
	m_type = Type::i8;
	m_mode = Constant;
}

__device__ CuString Integer::toString() const
{
	CuString str = m_value.toString() + typeName(m_type);
	str = str + "." + modeText(m_mode);
	return str;
}

__device__ void Integer::normalize()
{
	if (m_value < integerMin(m_type) || m_value > integerMax(m_type))
	{
		Integer tmp = Integer::fromBitsLe(m_type, toBitsLe());
		m_value = tmp.m_value;
	}
}

__device__ bool Integer::is_constant() const
{
	return m_mode == Constant;
}

__device__ bool Integer::is_signed() const
{
	return typeIsSign(m_type);
}

__device__ Boolean Integer::msb() const
{
	int ret = 0;
	if (bitSize() >= 32)
	{
		int mask = bitSize()/32 - 1;
		ret = m_value.data[mask] & (1 << 31);
	}
	else
	{
		ret = m_value.data[0] & (1U << (bitSize() - 1));
	}
	if (ret)
		return Boolean::create(m_mode, true);
	else
		return Boolean::create(m_mode, false);
}

__device__ Integer Integer::operator+(const Integer& other) const
{
	Integer ret;
	ret.m_mode = calcMode(this->m_mode, other.m_mode);
	ret.m_type = this->m_type;
	ret.m_value = this->m_value + other.m_value;
	ret.normalize();
	return ret;
}

__device__ Integer Integer::operator-(const Integer& other) const
{
	Integer ret;
	ret.m_mode = calcMode(this->m_mode, other.m_mode);
	ret.m_type = this->m_type;
	ret.m_value = this->m_value - other.m_value;
	ret.normalize();
	return ret;
}

__device__ Integer Integer::operator*(const Integer& other) const
{
	Integer ret;
	ret.m_mode = calcMode(this->m_mode, other.m_mode);
	ret.m_type = this->m_type;
	ret.m_value = this->m_value * other.m_value;
	ret.normalize();
	return ret;
}

__device__ Integer Integer::operator/(const Integer& other) const
{
	Integer ret;
	ret.m_mode = calcMode(this->m_mode, other.m_mode);
	ret.m_type = this->m_type;
	ret.m_value = this->m_value / other.m_value;
	ret.normalize();
	return ret;
}

__device__ Integer Integer::operator%(const Integer& other) const
{
	Integer ret;
	ret.m_mode = calcMode(this->m_mode, other.m_mode);
	ret.m_type = this->m_type;
	ret.m_value = this->m_value % other.m_value;
	ret.normalize();
	return ret;
}

__device__ Integer Integer::operator~() const
{
	BitArray buffer = toBitsLe();
	for (int i = 0; i < buffer.size(); i++)
	{
		buffer[i].value = !buffer[i].value;
	}
	return Integer::fromBitsLe(m_type, buffer);
}

__device__ bool Integer::operator==(const Integer& other) const
{
	return m_value == other.m_value;
}

__device__ bool Integer::operator<(const Integer& other) const
{
	return m_value < other.m_value;
}

__device__ Integer Integer::wrapping_shl(const Integer& other) const
{
	assert(0);
	return Integer();
}

__device__ Integer Integer::wrapping_shr(const Integer& other) const
{
	assert(0);
	return Integer();
}

__device__ BitArray Integer::toBitsLe() const
{
	CuByteArray b(bitSize()/8, 0);
	memcpy(b.data(), m_value.data, bitSize()/8);

	BitArray ret = bytes_to_bits_le(b);
	for (int i = 0; i < ret.size(); i++)
		ret[i].mode = m_mode;

	return ret;
}

__device__ cpp_int Integer::value() const
{
	return m_value;
}

__device__ Field Integer::toField() const
{
	return Field::fromBitsLe(toBitsLe());
}

__device__ Mode Integer::mode() const
{
	return m_mode;
}

__device__ void Integer::setMode(Mode mode)
{
	m_mode = mode;
}

__device__ int Integer::type() const
{
	return m_type;
}

__device__ int Integer::bitSize() const
{
	return typeBitSize(m_type);
}

__device__ Integer Integer::cast_as_dual() const
{
	Integer i = Integer::fromBitsLe(integerDualType(m_type), toBitsLe());
	return i;
}

__device__ Integer Integer::min() const
{
	return Integer::constant(m_type, integerMin(m_type));
}

__device__ Integer Integer::max() const
{
	return Integer::constant(m_type, integerMax(m_type));
}

__device__ CuDebug operator<<(CuDebug dbg, const Integer& i)
{
	dbg << i.toString();
	return dbg;
}

//Group
__device__ Group Group::zero()
{
	Group g;
	g.x = Field::zero();
	g.y = Field::constant(1);
	return g;
}

__device__ Group::Group()
{
}

__device__ bool Group::is_constant() const
{
	return x.is_constant() && y.is_constant();
}

__device__ bool Group::is_zero() const
{
	return x.b == 0 && y.b == 1;
}

__device__ Field booleanToField(Boolean b)
{
	Field f;
	f.mode = b.mode;
	f.b = b.value ? 1 : 0;
	return f;
}

__device__ Integer toInteger(const Field& f, int v_type)
{
	if (typeIsInteger(v_type))
	{
		Integer i = Integer::fromField(v_type, f);
		return i;
	}
	else
	{
		assert(0);
		return Integer();
	}
}

__device__ int integerDualType(int v_type)
{
	if (v_type == Type::i8)
		return Type::u8;
	else if (v_type == Type::i16)
		return Type::u16;
	else if (v_type == Type::i32)
		return Type::u32;
	else if (v_type == Type::i64)
		return Type::u64;
	else if (v_type == Type::i128)
		return Type::u128;
	else if (v_type == Type::u8)
		return Type::i8;
	else if (v_type == Type::u16)
		return Type::i16;
	else if (v_type == Type::u32)
		return Type::i32;
	else if (v_type == Type::u64)
		return Type::i64;
	else if (v_type == Type::u128)
		return Type::i128;

	assert(0);
	return 0;
}

__device__ cpp_int integerMin(int type_id)
{
	if (type_id == Type::i8)
		return INT8_MIN;
	else if (type_id == Type::i16)
		return INT16_MIN;
	else if (type_id == Type::i32)
		return INT32_MIN;
	else if (type_id == Type::i64)
		return INT64_MIN;
	else if (type_id == Type::i128)
	{
		return int128_t::MIN();
	}
	else if (type_id == Type::u8)
		return 0;
	else  if (type_id == Type::u16)
		return 0;
	else if (type_id == Type::u32)
		return 0;
	else if (type_id == Type::u64)
		return 0;
	else if (type_id == Type::u128)
		return 0;

	assert(0);
	return 0;
}

__device__ cpp_int integerMax(int type_id)
{
	if (type_id == Type::i8)
		return INT8_MAX;
	else if (type_id == Type::i16)
		return INT16_MAX;
	else if (type_id == Type::i32)
		return INT32_MAX;
	else if (type_id == Type::i64)
		return INT64_MAX;
	else if (type_id == Type::i128)
	{
		return int128_t::MAX();
	}
	else if (type_id == Type::u8)
		return UINT8_MAX;
	else  if (type_id == Type::u16)
		return UINT16_MAX;
	else if (type_id == Type::u32)
		return UINT32_MAX;
	else if (type_id == Type::u64)
		return UINT64_MAX;
	else if (type_id == Type::u128)
	{
		return (int256_t)(uint256_t)(uint128_t::MAX());
	}

	assert(0);
	return 0;
}